/*
 * 
 * 
 * 
 */
package com.hboxs.asl.entity;

import com.hboxs.asl.Constant;
import com.hboxs.asl.Setting;
import com.hboxs.asl.util.SettingUtils;
import com.hboxs.asl.wechat.entity.WxOrder;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

import javax.persistence.*;
import javax.validation.Valid;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.*;

/**
 * Entity - 订单
 */
@Entity
@Table(name = "xx_order")
@SequenceGenerator(name = "sequenceGenerator", sequenceName = "xx_order_sequence")
public class Order extends BaseEntity {

    private static final long serialVersionUID = 8370942500343156156L;

    /**
     * 订单名称分隔符
     */
    private static final String NAME_SEPARATOR = " ";

    /**
     * 订单状态
     */
    public enum OrderStatus {

        /**
         * 未确认
         */
        unconfirmed,

        /**
         * 已确认
         */
        confirmed,

        /**
         * 已完成
         */
        completed,

        /**
         * 已取消
         */
        cancelled
    }

    /**
     * 支付状态
     */
    public enum PaymentStatus {

        /**
         * 未支付
         */
        unpaid,

        /**
         * 部分支付
         */
        partialPayment,

        /**
         * 已支付
         */
        paid,

        /**
         * 部分退款
         */
        partialRefunds,

        /**
         * 已退款
         */
        refunded
    }

    /**
     * 配送状态
     */
    public enum ShippingStatus {

        /**
         * 未发货
         */
        unshipped,

        /**
         * 部分发货
         */
        partialShipment,

        /**
         * 已发货
         */
        shipped,

        /**
         * 部分退货
         */
        partialReturns,

        /**
         * 已退货
         */
        returned
    }

    /**
     * 订单编号
     */
    private String sn;

    /**
     * 订单状态
     */
    private OrderStatus orderStatus;

    /**
     * 支付状态
     */
    private PaymentStatus paymentStatus;

    /**
     * 配送状态
     */
    private ShippingStatus shippingStatus;

    /**
     * 支付手续费
     */
    private BigDecimal fee;

    /**
     * 运费
     */
    private BigDecimal freight;

    /**
     * 促销折扣
     */
    private BigDecimal promotionDiscount;

    /**
     * 优惠券折扣
     */
    private BigDecimal couponDiscount;

    /**
     * 调整金额
     */
    private BigDecimal offsetAmount;

    /**
     * 已付金额
     */
    private BigDecimal amountPaid;

    /**
     * 赠送积分
     */
    private BigDecimal point;

    /**
     * 赠送会员积分
     */
    private BigDecimal mPoint;

    /**
     * 支付积分
     */
    private BigDecimal payPoint;

    /**
     * 收货人
     */
    private String consignee;

    /**
     * 地区名称
     */
    private String areaName;

    /**
     * 地址
     */
    private String address;

    /**
     * 邮编
     */
    private String zipCode;

    /**
     * 电话
     */
    private String phone;

    /**
     * 是否开据发票
     */
    private Boolean isInvoice;

    /**
     * 发票抬头
     */
    private String invoiceTitle;

    /**
     * 税金
     */
    private BigDecimal tax;

    /**
     * 附言
     */
    private String memo;

    /**
     * 促销
     */
    private Promotion promotion;

    /**
     * 到期时间
     */
    private Date expire;

    /**
     * 锁定到期时间
     */
    private Date lockExpire;

    /**
     * 是否已分配库存
     */
    private Boolean isAllocatedStock;

    /**
     * 支付方式名称
     */
    private String paymentMethodName;

    /**
     * 配送方式名称
     */
    private String shippingMethodName;

    /**
     * 地区
     */
    private Area area;

    /**
     * 支付方式
     */
    private PaymentMethod paymentMethod;

    /**
     * 配送方式
     */
    private ShippingMethod shippingMethod;

    /**
     * 操作员
     */
    private Admin operator;

    /**
     * 操作商家
     */
    private Merchant operatorMerchant;

    /**
     * 会员
     */
    private Member member;

    /**
     * 优惠码
     */
    private CouponCode couponCode;

    /**
     * 完成时间
     */
    private Date completeDate;

    /**
     * 微信订单
     */
    private WxOrder wxOrder;

    @OneToOne(mappedBy = "orderxx", fetch = FetchType.LAZY)
    @JoinColumn(nullable = true, updatable = true)
    public WxOrder getWxOrder() {
        return wxOrder;
    }

    public void setWxOrder(WxOrder wxOrder) {
        this.wxOrder = wxOrder;
    }

    public Date getCompleteDate() {
        return completeDate;
    }

    public void setCompleteDate(Date completeDate) {
        this.completeDate = completeDate;
    }

    /**
     * 优惠券
     */
    private List<Coupon> coupons = new ArrayList<Coupon>();

    /**
     * 订单项
     */
    private List<OrderItem> orderItems = new ArrayList<OrderItem>();

    /**
     * 订单日志
     */
    private Set<OrderLog> orderLogs = new HashSet<OrderLog>();

    /**
     * 预存款
     */
    private Set<Deposit> deposits = new HashSet<Deposit>();

    /**
     * 收款单
     */
    private Set<Payment> payments = new HashSet<Payment>();

    /**
     * 退款单
     */
    private Set<Refunds> refunds = new HashSet<Refunds>();

    /**
     * 发货单
     */
    private Set<Shipping> shippings = new HashSet<Shipping>();

    /**
     * 退货单
     */
    private Set<Returns> returns = new HashSet<Returns>();

    /**
     * 获取订单编号
     *
     * @return 订单编号
     */
    @Column(nullable = false, updatable = false, unique = true, length = 100)
    public String getSn() {
        return sn;
    }

    /**
     * 设置订单编号
     *
     * @param sn 订单编号
     */
    public void setSn(String sn) {
        this.sn = sn;
    }

    /**
     * 获取订单状态
     *
     * @return 订单状态
     */
    @Column(nullable = false)
    public OrderStatus getOrderStatus() {
        return orderStatus;
    }

    /**
     * 设置订单状态
     *
     * @param orderStatus 订单状态
     */
    public void setOrderStatus(OrderStatus orderStatus) {
        this.orderStatus = orderStatus;
    }

    /**
     * 获取支付状态
     *
     * @return 支付状态
     */
    @Column(nullable = false)
    public PaymentStatus getPaymentStatus() {
        return paymentStatus;
    }

    /**
     * 设置支付状态
     *
     * @param paymentStatus 支付状态
     */
    public void setPaymentStatus(PaymentStatus paymentStatus) {
        this.paymentStatus = paymentStatus;
    }

    /**
     * 获取配送状态
     *
     * @return 配送状态
     */
    @Column(nullable = false)
    public ShippingStatus getShippingStatus() {
        return shippingStatus;
    }

    /**
     * 设置配送状态
     *
     * @param shippingStatus 配送状态
     */
    public void setShippingStatus(ShippingStatus shippingStatus) {
        this.shippingStatus = shippingStatus;
    }

    /**
     * 获取支付手续费
     *
     * @return 支付手续费
     */
    @Column(nullable = false, precision = 21, scale = 2)
    public BigDecimal getFee() {
        return fee;
    }

    /**
     * 设置支付手续费
     *
     * @param fee 支付手续费
     */
    public void setFee(BigDecimal fee) {
        this.fee = fee;
    }

    /**
     * 获取运费
     *
     * @return 运费
     */
    @NotNull
    @Min(0)
    @Digits(integer = 12, fraction = 3)
    @Column(nullable = false, precision = 21, scale = 2)
    public BigDecimal getFreight() {
        return freight;
    }

    /**
     * 设置运费
     *
     * @param freight 运费
     */
    public void setFreight(BigDecimal freight) {
        this.freight = freight;
    }

    /**
     * 获取促销折扣
     *
     * @return 促销折扣
     */
    @Column(nullable = false, updatable = false, precision = 21, scale = 2)
    public BigDecimal getPromotionDiscount() {
        return promotionDiscount;
    }

    /**
     * 设置促销折扣
     *
     * @param promotionDiscount 促销折扣
     */
    public void setPromotionDiscount(BigDecimal promotionDiscount) {
        this.promotionDiscount = promotionDiscount;
    }

    /**
     * 获取优惠券折扣
     *
     * @return 优惠券折扣
     */
    @Column(nullable = false, updatable = false, precision = 21, scale = 2)
    public BigDecimal getCouponDiscount() {
        return couponDiscount;
    }

    /**
     * 设置优惠券折扣
     *
     * @param couponDiscount 优惠券折扣
     */
    public void setCouponDiscount(BigDecimal couponDiscount) {
        this.couponDiscount = couponDiscount;
    }

    /**
     * 获取调整金额
     *
     * @return 调整金额
     */
    public BigDecimal getOffsetAmount() {
        return offsetAmount;
    }

    /**
     * 设置调整金额
     *
     * @param offsetAmount 调整金额
     */
    public void setOffsetAmount(BigDecimal offsetAmount) {
        this.offsetAmount = offsetAmount;
    }

    /**
     * 获取已付金额
     *
     * @return 已付金额
     */
    @Column(nullable = false, precision = 21, scale = 2)
    public BigDecimal getAmountPaid() {
        return amountPaid;
    }

    /**
     * 设置已付金额
     *
     * @param amountPaid 已付金额
     */
    public void setAmountPaid(BigDecimal amountPaid) {
        this.amountPaid = amountPaid;
    }

    /**
     * 获取赠送积分
     *
     * @return 赠送积分
     */
    @Min(0)
    @Column(nullable = false)
    public BigDecimal getPoint() {
        return point;
    }

    /**
     * 设置赠送积分
     *
     * @param point 赠送积分
     */
    @Min(0)
    @Column(nullable = false)
    public void setPoint(BigDecimal point) {
        this.point = point;
    }
    @Min(0)
    public BigDecimal getmPoint() {
        return mPoint;
    }
    @Min(0)
    public void setmPoint(BigDecimal mPoint) {
        this.mPoint = mPoint;
    }

    /**
     * 获取支付积分
     *
     * @return 支付积分
     */
    public BigDecimal getPayPoint() {
        return payPoint;
    }

    /**
     * 设置支付积分
     *
     * @param payPoint 支付积分
     */
    public void setPayPoint(BigDecimal payPoint) {
        this.payPoint = payPoint;
    }

    /**
     * 获取收货人
     *
     * @return 收货人
     */
    @NotEmpty
    @Length(max = 200)
    @Column(nullable = false)
    public String getConsignee() {
        return consignee;
    }

    /**
     * 设置收货人
     *
     * @param consignee 收货人
     */
    public void setConsignee(String consignee) {
        this.consignee = consignee;
    }

    /**
     * 获取地区名称
     *
     * @return 地区名称
     */
    @Column(nullable = false)
    public String getAreaName() {
        return areaName;
    }

    /**
     * 设置地区名称
     *
     * @param areaName 地区名称
     */
    public void setAreaName(String areaName) {
        this.areaName = areaName;
    }

    /**
     * 获取地址
     *
     * @return 地址
     */
    @NotEmpty
    @Length(max = 200)
    @Column(nullable = false)
    public String getAddress() {
        return address;
    }

    /**
     * 设置地址
     *
     * @param address 地址
     */
    public void setAddress(String address) {
        this.address = address;
    }

    /**
     * 获取邮编
     *
     * @return 邮编
     */
    @NotEmpty
    @Length(max = 200)
    @Column(nullable = false)
    public String getZipCode() {
        return zipCode;
    }

    /**
     * 设置邮编
     *
     * @param zipCode 邮编
     */
    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    /**
     * 获取电话
     *
     * @return 电话
     */
    @NotEmpty
    @Length(max = 200)
    @Column(nullable = false)
    public String getPhone() {
        return phone;
    }

    /**
     * 设置电话
     *
     * @param phone 电话
     */
    public void setPhone(String phone) {
        this.phone = phone;
    }

    /**
     * 获取是否开据发票
     *
     * @return 是否开据发票
     */
//    @NotNull
    @Column(nullable = false)
    public Boolean getIsInvoice() {
        return isInvoice;
    }

    /**
     * 设置是否开据发票
     *
     * @param isInvoice 是否开据发票
     */
    public void setIsInvoice(Boolean isInvoice) {
        this.isInvoice = isInvoice;
    }

    /**
     * 获取发票抬头
     *
     * @return 发票抬头
     */
    @Length(max = 200)
    public String getInvoiceTitle() {
        return invoiceTitle;
    }

    /**
     * 设置发票抬头
     *
     * @param invoiceTitle 发票抬头
     */
    public void setInvoiceTitle(String invoiceTitle) {
        this.invoiceTitle = invoiceTitle;
    }

    /**
     * 获取税金
     *
     * @return 税金
     */
    @Min(0)
    public BigDecimal getTax() {
        return tax;
    }

    /**
     * 设置税金
     *
     * @param tax 税金
     */
    public void setTax(BigDecimal tax) {
        this.tax = tax;
    }

    /**
     * 获取附言
     *
     * @return 附言
     */
    @Length(max = 200)
    public String getMemo() {
        return memo;
    }

    /**
     * 设置附言
     *
     * @param memo 附言
     */
    public void setMemo(String memo) {
        this.memo = memo;
    }

    /**
     * 获取促销
     *
     * @return 促销
     */
    @ManyToOne(fetch = FetchType.LAZY)
    public Promotion getPromotion() {
        return promotion;
    }

    /**
     * 设置促销
     *
     * @param promotion 促销
     */
    public void setPromotion(Promotion promotion) {
        this.promotion = promotion;
    }

    /**
     * 获取到期时间
     *
     * @return 到期时间
     */
    public Date getExpire() {
        return expire;
    }

    /**
     * 设置到期时间
     *
     * @param expire 到期时间
     */
    public void setExpire(Date expire) {
        this.expire = expire;
    }

    /**
     * 获取锁定到期时间
     *
     * @return 锁定到期时间
     */
    public Date getLockExpire() {
        return lockExpire;
    }

    /**
     * 设置锁定到期时间
     *
     * @param lockExpire 锁定到期时间
     */
    public void setLockExpire(Date lockExpire) {
        this.lockExpire = lockExpire;
    }

    /**
     * 获取是否已分配库存
     *
     * @return 是否已分配库存
     */
    @Column(nullable = false)
    public Boolean getIsAllocatedStock() {
        return isAllocatedStock;
    }

    /**
     * 设置是否已分配库存
     *
     * @param isAllocatedStock 是否已分配库存
     */
    public void setIsAllocatedStock(Boolean isAllocatedStock) {
        this.isAllocatedStock = isAllocatedStock;
    }

    /**
     * 获取支付方式名称
     *
     * @return 支付方式名称
     */
    @Column(nullable = false)
    public String getPaymentMethodName() {
        return paymentMethodName;
    }

    /**
     * 设置支付方式名称
     *
     * @param paymentMethodName 支付方式名称
     */
    public void setPaymentMethodName(String paymentMethodName) {
        this.paymentMethodName = paymentMethodName;
    }

    /**
     * 获取配送方式名称
     *
     * @return 配送方式名称
     */
    @Column(nullable = false)
    public String getShippingMethodName() {
        return shippingMethodName;
    }

    /**
     * 设置配送方式名称
     *
     * @param shippingMethodName 配送方式名称
     */
    public void setShippingMethodName(String shippingMethodName) {
        this.shippingMethodName = shippingMethodName;
    }

    /**
     * 获取地区
     *
     * @return 地区
     */
    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    public Area getArea() {
        return area;
    }

    /**
     * 设置地区
     *
     * @param area 地区
     */
    public void setArea(Area area) {
        this.area = area;
    }

    /**
     * 获取支付方式
     *
     * @return 支付方式
     */
    @ManyToOne(fetch = FetchType.LAZY)
    public PaymentMethod getPaymentMethod() {
        return paymentMethod;
    }

    /**
     * 设置支付方式
     *
     * @param paymentMethod 支付方式
     */
    public void setPaymentMethod(PaymentMethod paymentMethod) {
        this.paymentMethod = paymentMethod;
    }

    /**
     * 获取配送方式
     *
     * @return 配送方式
     */
    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    public ShippingMethod getShippingMethod() {
        return shippingMethod;
    }

    /**
     * 设置配送方式
     *
     * @param shippingMethod 配送方式
     */
    public void setShippingMethod(ShippingMethod shippingMethod) {
        this.shippingMethod = shippingMethod;
    }

    /**
     * 获取操作员
     *
     * @return 操作员
     */
    @ManyToOne(fetch = FetchType.LAZY)
    public Admin getOperator() {
        return operator;
    }

    /**
     * 设置操作员
     *
     * @param operator 操作员
     */
    public void setOperator(Admin operator) {
        this.operator = operator;
    }

    /**
     * 获取操作商家
     *
     * @return 操作商家
     */
    @ManyToOne(fetch = FetchType.LAZY)
    public Merchant getOperatorMerchant() {
        return operatorMerchant;
    }

    /**
     * 设置操作商家
     *
     * @param operatorMerchant 操作商家
     */
    public void setOperatorMerchant(Merchant operatorMerchant) {
        this.operatorMerchant = operatorMerchant;
    }

    /**
     * 获取会员
     *
     * @return 会员
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = false, updatable = false)
    public Member getMember() {
        return member;
    }

    /**
     * 设置会员
     *
     * @param member 会员
     */
    public void setMember(Member member) {
        this.member = member;
    }

    /**
     * 获取优惠码
     *
     * @return 优惠码
     */
    @ManyToOne(fetch = FetchType.LAZY)
    public CouponCode getCouponCode() {
        return couponCode;
    }

    /**
     * 设置优惠码
     *
     * @param couponCode 优惠码
     */
    public void setCouponCode(CouponCode couponCode) {
        this.couponCode = couponCode;
    }

    /**
     * 获取优惠券
     *
     * @return 优惠券
     */
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "xx_order_coupon")
    public List<Coupon> getCoupons() {
        return coupons;
    }

    /**
     * 设置优惠券
     *
     * @param coupons 优惠券
     */
    public void setCoupons(List<Coupon> coupons) {
        this.coupons = coupons;
    }

    /**
     * 获取订单项
     *
     * @return 订单项
     */
    @Valid
    @NotEmpty
    @OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    public List<OrderItem> getOrderItems() {
        return orderItems;
    }

    /**
     * 设置订单项
     *
     * @param orderItems 订单项
     */
    public void setOrderItems(List<OrderItem> orderItems) {
        this.orderItems = orderItems;
    }

    /**
     * 获取订单日志
     *
     * @return 订单日志
     */
    @OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @OrderBy("createDate asc")
    public Set<OrderLog> getOrderLogs() {
        return orderLogs;
    }

    /**
     * 设置订单日志
     *
     * @param orderLogs 订单日志
     */
    public void setOrderLogs(Set<OrderLog> orderLogs) {
        this.orderLogs = orderLogs;
    }

    /**
     * 获取预存款
     *
     * @return 预存款
     */
    @OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
    public Set<Deposit> getDeposits() {
        return deposits;
    }

    /**
     * 设置预存款
     *
     * @param deposits 预存款
     */
    public void setDeposits(Set<Deposit> deposits) {
        this.deposits = deposits;
    }

    /**
     * 获取收款单
     *
     * @return 收款单
     */
    @OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @OrderBy("createDate asc")
    public Set<Payment> getPayments() {
        return payments;
    }

    /**
     * 设置收款单
     *
     * @param payments 收款单
     */
    public void setPayments(Set<Payment> payments) {
        this.payments = payments;
    }

    /**
     * 获取退款单
     *
     * @return 退款单
     */
    @OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @OrderBy("createDate asc")
    public Set<Refunds> getRefunds() {
        return refunds;
    }

    /**
     * 设置退款单
     *
     * @param refunds 退款单
     */
    public void setRefunds(Set<Refunds> refunds) {
        this.refunds = refunds;
    }

    /**
     * 获取发货单
     *
     * @return 发货单
     */
    @OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @OrderBy("createDate asc")
    public Set<Shipping> getShippings() {
        return shippings;
    }

    /**
     * 设置发货单
     *
     * @param shippings 发货单
     */
    public void setShippings(Set<Shipping> shippings) {
        this.shippings = shippings;
    }

    /**
     * 获取退货单
     *
     * @return 退货单
     */
    @OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @OrderBy("createDate asc")
    public Set<Returns> getReturns() {
        return returns;
    }

    /**
     * 设置退货单
     *
     * @param returns 退货单
     */
    public void setReturns(Set<Returns> returns) {
        this.returns = returns;
    }

    /**
     * 获取订单名称
     *
     * @return 订单名称
     */
    @Transient
    public String getName() {
        StringBuffer name = new StringBuffer();
        if (getOrderItems() != null) {
            for (OrderItem orderItem : getOrderItems()) {
                if (orderItem != null && orderItem.getFullName() != null) {
                    name.append(NAME_SEPARATOR).append(orderItem.getFullName());
                }
            }
            if (name.length() > 0) {
                name.deleteCharAt(0);
            }
        }
        return name.toString();
    }

    /**
     * 获取商品重量
     *
     * @return 商品重量
     */
    @Transient
    public int getWeight() {
        int weight = 0;
        if (getOrderItems() != null) {
            for (OrderItem orderItem : getOrderItems()) {
                if (orderItem != null) {
                    weight += orderItem.getTotalWeight();
                }
            }
        }
        return weight;
    }

    /**
     * 获取商品数量
     *
     * @return 商品数量
     */
    @Transient
    public int getQuantity() {
        int quantity = 0;
        if (getOrderItems() != null) {
            for (OrderItem orderItem : getOrderItems()) {
                if (orderItem != null && orderItem.getQuantity() != null) {
                    quantity += orderItem.getQuantity();
                }
            }
        }
        return quantity;
    }

    /**
     * 获取已发货数量
     *
     * @return 已发货数量
     */
    @Transient
    public int getShippedQuantity() {
        int shippedQuantity = 0;
        if (getOrderItems() != null) {
            for (OrderItem orderItem : getOrderItems()) {
                if (orderItem != null && orderItem.getShippedQuantity() != null) {
                    shippedQuantity += orderItem.getShippedQuantity();
                }
            }
        }
        return shippedQuantity;
    }

    /**
     * 获取已退货数量
     *
     * @return 已退货数量
     */
    @Transient
    public int getReturnQuantity() {
        int returnQuantity = 0;
        if (getOrderItems() != null) {
            for (OrderItem orderItem : getOrderItems()) {
                if (orderItem != null && orderItem.getReturnQuantity() != null) {
                    returnQuantity += orderItem.getReturnQuantity();
                }
            }
        }
        return returnQuantity;
    }

    /**
     * 获取
     *
     *
     * @return 商品价格
     */
    @Transient
    public BigDecimal getPrice() {
        BigDecimal price = new BigDecimal(0);
        if (getOrderItems() != null) {
            for (OrderItem orderItem : getOrderItems()) {
                if (orderItem != null && orderItem.getSubtotal() != null) {
                    price = price.add(orderItem.getSubtotal());
                }
            }
        }
        return price;
    }

    /**
     * 获取订单金额
     *
     * @return 订单金额
     */
    @Transient
    public BigDecimal getAmount() {
        BigDecimal amount = getPrice();
        if (getFee() != null) {
            amount = amount.add(getFee());
        }
        if (getFreight() != null) {
            amount = amount.add(getFreight());
        }
        if (getPromotionDiscount() != null) {
            amount = amount.subtract(getPromotionDiscount());
        }
        if (getCouponDiscount() != null) {
            amount = amount.subtract(getCouponDiscount());
        }
        if (getOffsetAmount() != null) {
            amount = amount.add(getOffsetAmount());
        }
        if (getTax() != null) {
            amount = amount.add(getTax());
        }
        //减去使用积分抵扣订单商品的价格
        if (getPayPoint() != null) {
            amount = amount.subtract(getPayPoint().divide(Constant.POINT_SCALE));
        }
        return amount.compareTo(new BigDecimal(0)) > 0 ? amount : new BigDecimal(0);
    }

    /**
     * 获取应付金额
     *
     * @return 应付金额
     */
    @Transient
    public BigDecimal getAmountPayable() {
        BigDecimal amountPayable = getAmount().subtract(getAmountPaid());
        return amountPayable.compareTo(new BigDecimal(0)) > 0 ? amountPayable : new BigDecimal(0);
    }

    /**
     * 是否已过期
     *
     * @return 是否已过期
     */
    @Transient
    public boolean isExpired() {
        return getExpire() != null && new Date().after(getExpire());
    }

    /**
     * 获取订单项
     *
     * @param sn 商品编号
     * @return 订单项
     */
    @Transient
    public OrderItem getOrderItem(String sn) {
        if (sn != null && getOrderItems() != null) {
            for (OrderItem orderItem : getOrderItems()) {
                if (orderItem != null && sn.equalsIgnoreCase(orderItem.getSn())) {
                    return orderItem;
                }
            }
        }
        return null;
    }

    /**
     * 判断是否已锁定
     *
     * @param operator 操作员
     * @return 是否已锁定
     */
    @Transient
    public boolean isLocked(Admin operator) {
        return getLockExpire() != null && new Date().before(getLockExpire()) && ((operator != null && !operator.equals(getOperator())) || (operator == null && getOperator() != null));
    }


    /**
     * 判断是否已锁定
     *
     * @param operatorMerchant 操作商家
     * @return 是否已锁定
     */
    @Transient
    public boolean isMerchantLocked(Merchant operatorMerchant) {
        return getLockExpire() != null && new Date().before(getLockExpire()) && ((operatorMerchant != null && !operatorMerchant.equals(getOperatorMerchant())) || (operatorMerchant == null && getOperatorMerchant() != null));
    }


    /**
     * 计算税金
     *
     * @return 税金
     */
    @Transient
    public BigDecimal calculateTax() {
        BigDecimal tax = new BigDecimal(0);
        Setting setting = SettingUtils.get();
        if (setting.getIsTaxPriceEnabled()) {
            BigDecimal amount = getPrice();
            if (getPromotionDiscount() != null) {
                amount = amount.subtract(getPromotionDiscount());
            }
            if (getCouponDiscount() != null) {
                amount = amount.subtract(getCouponDiscount());
            }
            if (getOffsetAmount() != null) {
                amount = amount.add(getOffsetAmount());
            }
            tax = amount.multiply(new BigDecimal(setting.getTaxRate().toString()));
        }
        return setting.setScale(tax);
    }

    /**
     * 持久化前处理
     */
    @PrePersist
    public void prePersist() {
        if (getArea() != null) {
            setAreaName(getArea().getFullName());
        }
        if (getPaymentMethod() != null) {
            setPaymentMethodName(getPaymentMethod().getName());
        }
        if (getShippingMethod() != null) {
            setShippingMethodName(getShippingMethod().getName());
        }
    }

    /**
     * 更新前处理
     */
    @PreUpdate
    public void preUpdate() {
        if (getArea() != null) {
            setAreaName(getArea().getFullName());
        }
        if (getPaymentMethod() != null) {
            setPaymentMethodName(getPaymentMethod().getName());
        }
        if (getShippingMethod() != null) {
            setShippingMethodName(getShippingMethod().getName());
        }
    }

    /**
     * 删除前处理
     */
    @PreRemove
    public void preRemove() {
        Set<Deposit> deposits = getDeposits();
        if (deposits != null) {
            for (Deposit deposit : deposits) {
                deposit.setOrder(null);
            }
        }
    }

    /**
     * 获取订单信息
     */
    @Transient
    public String getDetails() {
        StringBuilder sb = new StringBuilder(" ");
        for (OrderItem o : getOrderItems()) {
            sb.append(o.getFullName());
            sb.append("/");
        }
        return sb.substring(0, sb.length() - 1).trim();
    }

    /**
     * 获取显示状态//改成数字，不要骂我
     */
    @Transient
    public String getDisplayStatus() {

        //订单正常走流程过期时间会置空,否则证明未支付
        if (this.isExpired()) {
            return "已过期";
        }

        if (OrderStatus.confirmed.equals(this.getOrderStatus())
                && PaymentStatus.unpaid.equals(this.getPaymentStatus())
                && ShippingStatus.unshipped.equals(this.getShippingStatus())
                ) {
            return "去支付";
        } else if (OrderStatus.confirmed.equals(this.getOrderStatus())
                && PaymentStatus.paid.equals(this.getPaymentStatus())
                && ShippingStatus.unshipped.equals(this.getShippingStatus())) {
            return "待发货";
        } else if (OrderStatus.confirmed.equals(this.getOrderStatus())
                && PaymentStatus.paid.equals(this.getPaymentStatus())
                && ShippingStatus.shipped.equals(this.getShippingStatus())) {
            return "确认收货";
        } else if (OrderStatus.completed.equals(this.getOrderStatus())
                && PaymentStatus.paid.equals(this.getPaymentStatus())
                && ShippingStatus.shipped.equals(this.getShippingStatus())) {
            return "去评价";
        } else if (OrderStatus.cancelled.equals(this.getOrderStatus())) {
            return "已取消";
        } else if (ShippingStatus.returned.equals(this.getShippingStatus())) {
            return "已退货";
        } else if (ShippingStatus.partialReturns.equals(this.getShippingStatus())) {
            return "部分退货";
        } else if (PaymentStatus.refunded.equals(this.getPaymentStatus())) {
            return "已退款";
        } else if (PaymentStatus.partialRefunds.equals(this.getPaymentStatus())) {
            return "部分退款";
        } else {
            return "状态非法";
        }
    }


    /**
     * 获取不参与促销的购物车项
     */
    @Transient
    public Set<OrderItem> getOrderItemsWithoutPromotion() {
        List<OrderItem> cis = this.getOrderItems();
        Set<OrderItem> results = new HashSet<>();
        for (OrderItem ci : cis) {
            Product p = ci.getProduct();
            if (
                    (p.getPromotions() != null && p.getPromotions().size() > 0)
                            ||
                            (p.getProductCategory() != null && p.getProductCategory().getPromotions() != null && p.getProductCategory().getPromotions().size() > 0)
                    ) {
            } else {
                results.add(ci);
            }
        }
        return results;
    }

    /**
     * 获取参与促销的购物车项
     */
    @Transient
    public Set<OrderItem> getOrderItemsWithPromotion() {
        List<OrderItem> cis = this.getOrderItems();
        Set<OrderItem> results = new HashSet<>();
        for (OrderItem ci : cis) {
            Product p = ci.getProduct();
            if (
                    (p.getPromotions() != null && p.getPromotions().size() > 0)
                            ||
                            (p.getProductCategory() != null && p.getProductCategory().getPromotions() != null && p.getProductCategory().getPromotions().size() > 0)
                    ) {
                results.add(ci);
            } else {

            }
        }
        return results;
    }


    /**
     * 获取不参与促销的购物车项
     */
    @Transient
    public Set<OrderItem> getOrderItemsWithoutPromotion(Promotion promotion) {
        List<OrderItem> cis = this.getOrderItems();
        Set<OrderItem> results = new HashSet<>();
        for (OrderItem ci : cis) {
            Product p = ci.getProduct();
            if (
                    (p.getPromotions() != null && p.getPromotions().size() > 0 && p.getPromotions().contains(promotion))
                            ||
                            (p.getProductCategory() != null && p.getProductCategory().getPromotions() != null && p.getProductCategory().getPromotions().size() > 0 && p.getProductCategory().getPromotions().contains(promotion))
                    ) {
            } else {
                results.add(ci);
            }
        }
        return results;
    }

    /**
     * 获取参与促销的购物车项
     */
    @Transient
    public Set<OrderItem> getOrderItemsWithPromotion(Promotion promotion) {
        List<OrderItem> cis = this.getOrderItems();
        Set<OrderItem> results = new HashSet<>();
        for (OrderItem ci : cis) {
            Product p = ci.getProduct();
            if (
                    (p.getPromotions() != null && p.getPromotions().size() > 0 && p.getPromotions().contains(promotion))
                            ||
                            (p.getProductCategory() != null && p.getProductCategory().getPromotions() != null && p.getProductCategory().getPromotions().size() > 0 && p.getProductCategory().getPromotions().contains(promotion))
                    ) {
                results.add(ci);
            } else {

            }
        }
        return results;
    }


    /**
     * 获取不参加促销部分的小计
     *
     * @return 小计
     */
    @Transient
    public BigDecimal getSubtotalWithoutPromotion() {
        BigDecimal price = new BigDecimal(0);
        //1.获取购物车项集合并且移除使用了促销的购物车项
        List<OrderItem> cis = getOrderItems();
        //2.计算非促销购物车项的价格
        for (OrderItem c : this.getOrderItemsWithoutPromotion()) {
            if (c != null && c.getSubtotal() != null) {
                price = price.add(c.getSubtotal());
            }
        }
        return price;
    }

    /**
     * 获取不参加促销部分的小计
     *
     * @return 小计
     */
    @Transient
    public BigDecimal getSubtotalWithoutPromotion(Promotion promotion) {
        BigDecimal price = new BigDecimal(0);
        //1.获取购物车项集合并且移除使用了促销的购物车项
        List<OrderItem> cis = getOrderItems();
        //2.计算非促销购物车项的价格
        for (OrderItem c : this.getOrderItemsWithoutPromotion(promotion)) {
            if (c != null && c.getSubtotal() != null) {
                price = price.add(c.getSubtotal());
            }
        }
        return price;
    }

    /**
     * 获取参加促销部分的小计
     *
     * @return 小计
     */
    @Transient
    public BigDecimal getSubtotalWithPromotion(Promotion promotion) {
        BigDecimal price = new BigDecimal(0);
        //1.获取购物车项集合并且移除使用了促销的购物车项
        List<OrderItem> cis = getOrderItems();
        //2.计算促销购物车项的价格
        for (OrderItem c : this.getOrderItemsWithPromotion(promotion)) {
            if (c != null && c.getSubtotal() != null) {
                price = price.add(c.getSubtotal());
            }
        }
        return price;
    }

    /**
     * 是否已申请退货
     */
    @Transient
    public Boolean getReturnStatus() {
        Boolean status = false;
        for (OrderItem oi : this.getOrderItems()) {
            if (oi.getHasApplyReturn()) {
                status = true;
            }
        }
        return status;
    }

    /**
     * 状态枚举数字
     */
    @Transient
    public int getOrderStatusOrdinal() {
        return this.getOrderStatus().ordinal();
    }

    @Transient
    public int getPaymentStatusOrdinal() {
        return this.getPaymentStatus().ordinal();
    }

    @Transient
    public int getShippingStatusOrdinal() {
        return this.getShippingStatus().ordinal();
    }

    @Transient
    public boolean getIsExpired(){
        return isExpired();
    }
}